#include "StdAfx.h"
#include "ClientSocket.h"

CClientSocket::CClientSocket(BOOL bClient/* =TRUE */)
: m_bConnected(FALSE)
, m_pfnCallback(NULL)
, m_wParam(0)
, m_lParam(0)
, m_lEvent(FD_CLOSE)
{
	if (bClient) Create(0, SOCK_STREAM, FD_CONNECT | FD_CLOSE);
	else m_bConnected=TRUE;
}

CClientSocket::~CClientSocket(void)
{
	Close();
}

void CClientSocket::SetCallback(PFNCALLBACK pfnCallback, WPARAM wParam/* =0 */, LPARAM lParam/* =0 */)
{
	m_pfnCallback=pfnCallback;
	m_wParam=wParam;
	m_lParam=lParam;
}

BOOL CClientSocket::IsConnected()
{
	return m_bConnected;
}

BOOL CClientSocket::BeginSend(char *pBuf, int nBufLen)
{
	if (!m_bConnected) return FALSE;

	DATA ds;

	ds.pBuf=new char[nBufLen];
	ds.nBufLen=nBufLen;
	memcpy(ds.pBuf, pBuf, nBufLen);
	m_listSend.AddTail(ds);
	m_lEvent|=FD_WRITE;
	AsyncSelect(m_lEvent);
	return TRUE;
}

BOOL CClientSocket::BeginReceive(char *pBuf, int nBufLen)
{
	if (!m_bConnected) return FALSE;

	DATA dr={pBuf, nBufLen};

	m_listRecv.AddTail(dr);
	m_lEvent|=FD_READ;
	AsyncSelect(m_lEvent);
	return TRUE;
}

void CClientSocket::Close()
{
	m_bConnected=FALSE;
	ShutDown(both);
	while (!m_listSend.IsEmpty())
	{
		DATA ds=m_listSend.RemoveHead();

		delete[] ds.pBuf;
	}
	m_listRecv.RemoveAll();

	CAsyncSocket::Close();
}

void CClientSocket::OnConnect(int nErrorCode)
{
	if (nErrorCode==0)
	{
		m_bConnected=TRUE;
		if (m_pfnCallback!=NULL) m_pfnCallback(this, FD_CONNECT, m_wParam, m_lParam);
	}

	CAsyncSocket::OnConnect(nErrorCode);
}

void CClientSocket::OnClose(int nErrorCode)
{
	if (nErrorCode==0)
	{
		Close();
		Create(0, SOCK_STREAM, FD_CONNECT | FD_CLOSE);
		if (m_pfnCallback!=NULL) m_pfnCallback(this, FD_CLOSE, m_wParam, m_lParam);
	}

	CAsyncSocket::OnClose(nErrorCode);
}

void CClientSocket::OnSend(int nErrorCode)
{
	if (nErrorCode==0)
	{
		m_lEvent&=~FD_WRITE;
		AsyncSelect(m_lEvent);
		while (!m_listSend.IsEmpty())
		{
			DATA ds=m_listSend.RemoveHead();
			int nSendRes=0, nSendLen=0;

			while (nSendRes!=SOCKET_ERROR && nSendLen<ds.nBufLen)
			{
				nSendRes=Send(ds.pBuf+nSendLen, ds.nBufLen-nSendLen);
				nSendLen+=nSendRes;
			}
			delete[] ds.pBuf;
			if (m_pfnCallback!=NULL && nSendRes!=SOCKET_ERROR) m_pfnCallback(this, FD_WRITE, m_wParam, m_lParam);
		}
	}

	CAsyncSocket::OnSend(nErrorCode);
}

void CClientSocket::OnReceive(int nErrorCode)
{
	if (nErrorCode==0)
	{
		static bool bRecvEnd=true;
		static int nRecvLen=0;
		static DATA dr;

		if (bRecvEnd)
		{
			if(!m_listRecv.IsEmpty())
				dr=m_listRecv.RemoveHead();
			bRecvEnd=false;
		}
		nRecvLen+=Receive(dr.pBuf+nRecvLen, dr.nBufLen-nRecvLen);
		if (nRecvLen>=dr.nBufLen)
		{
			bRecvEnd=true;
			nRecvLen=0;
			if (m_listRecv.IsEmpty())
			{
				m_lEvent&=~FD_READ;
				AsyncSelect(m_lEvent);
			}
			
			if (m_pfnCallback!=NULL) m_pfnCallback(this, FD_READ, m_wParam, m_lParam);
		}
	}

	CAsyncSocket::OnReceive(nErrorCode);
}
